package com.icesoft.core.web.suppose.safehttp.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.SM2;
import com.icesoft.core.common.util.MD5Util;
import com.icesoft.core.web.helper.PathUtil;
import com.icesoft.core.web.model.CryptoKeyPair;
import com.icesoft.core.web.suppose.safehttp.SafeRequestConst;
import com.icesoft.core.web.suppose.safehttp.service.ICryptoKeyPairRepository;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

@ConditionalOnProperty(name = "icesoft.safe.sm-crypto-enable", havingValue = "true")
@Configuration
@Slf4j
class SmKeyAutoReadOrCreateBean {
    private static final String DEFAULT_KEY_PATH = "key/sm2KeyHex";

    SmKeyAutoReadOrCreateBean(ICryptoKeyPairRepository cryptoKeyPairRepository) {
        SM2 sm2 = readOrCreateKeyPair(PathUtil.getProjectRootPath() + DEFAULT_KEY_PATH);
        String defaultKeyId = MD5Util.md5(sm2.getPrivateKey().getEncoded());
        CryptoKeyPair cryptoKeyPair = new CryptoKeyPair();
        cryptoKeyPair.setPrivateKey(HexUtil.encodeHexStr(sm2.getPrivateKey().getEncoded()));
        cryptoKeyPair.setPublicKey(HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false)));
        cryptoKeyPair.setKeyId(defaultKeyId);
        cryptoKeyPair.setAlgorithm(SafeRequestConst.ALGORITHM_SM);
        cryptoKeyPairRepository.saveKey(cryptoKeyPair);
    }

    private static SM2 readOrCreateKeyPair(String keyFilePath) {
        SM2 sm2;
        if (FileUtil.exist(keyFilePath)) {
            List<String> lines = FileUtil.readLines(keyFilePath, Charset.defaultCharset());
            sm2 = SmUtil.sm2(lines.get(0), lines.get(1));
            FileUtil.writeLines(Arrays.asList(
                    HexUtil.encodeHexStr(sm2.getPrivateKey().getEncoded())
                    , HexUtil.encodeHexStr(sm2.getPublicKey().getEncoded())
                    , HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()))
                    , HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false))
            ), keyFilePath, Charset.defaultCharset());
            log.info("密钥文件加载成功：{}", keyFilePath);
        } else {
            sm2 = SmUtil.sm2();
            FileUtil.writeLines(Arrays.asList(
                    HexUtil.encodeHexStr(sm2.getPrivateKey().getEncoded())
                    , HexUtil.encodeHexStr(sm2.getPublicKey().getEncoded())
                    , HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()))
                    , HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false))
            ), keyFilePath, Charset.defaultCharset());
            log.info("密钥文件文件不存在，自动生成新的密钥文件：{}", keyFilePath);
        }
        return sm2;
    }
}